package com.avsdk;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Typeface;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.List;

/**
 * 展示摄像头数据
 */
public class VideoCap {
    int nWidth = 1280;
    int nHeight = 720;
    int orientation = 90;
    static public int getwidth = 0;
    static public int getheight = 0;
    static public int getformat = 0;
    static public int getsize = 0;
    private Canvas mCanvas = null;
    private SurfaceHolder mholder = null;
    SurfaceView mview = null;
    boolean bDraw;
    Camera mCamera = null;
    boolean mbfront = true;
    private int bytesPerPackage;
    private byte[] videoBuffer;
    AVCapCallBack mavcapcallback = null;
    String mosd = "";
    int mcolor;
    Typeface mfont;
    nativeSurfaceListener hoderlisten;

    public void StartCapture(SurfaceView view, int width, int height, boolean bfront, AVCapCallBack avcapcallback) {
        nWidth = width;
        nHeight = height;
        bytesPerPackage = nWidth * nHeight * 3 / 2;
        videoBuffer = new byte[bytesPerPackage];

        mavcapcallback = avcapcallback;
        mview = view;
        bDraw = true;
        mholder = mview.getHolder();
        mholder.setFormat(PixelFormat.TRANSLUCENT);
        hoderlisten = new nativeSurfaceListener();
        mholder.addCallback(hoderlisten);
        mholder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mbfront = bfront;
        OpenCam(mholder, bfront);
        initCamera();
    }

    int mx;
    int my;
    int mtextsize;

    public void SetOSD(String osd, int x, int y, Typeface font, int color, int textsize) {
        mosd = osd;
        mx = x;
        my = y;
        mtextsize = textsize;
        mfont = font;
        mcolor = color;
    }

    //设置摄像头旋转预览
    public void SetOrientation(int orientation) {
        this.orientation = orientation;
    }


    public void StopCapture() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
        mholder.removeCallback(hoderlisten);
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    boolean bIfPreview = false;

    private void initCamera() {
        if (bIfPreview) {
            mCamera.stopPreview();
        }
        if (null != mCamera) {
            try {

                Camera.Parameters parameters = mCamera.getParameters();
                parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);
                List<Size> previewSizes = mCamera.getParameters().getSupportedPreviewSizes();
                Size psize = null;
                boolean bfind = false;
                int setheight = 0;

                for (int i = 0; i < previewSizes.size(); i++) {
                    psize = previewSizes.get(i);

                    if (psize.width == nWidth) {
                        if (psize.height == nHeight) {
                            bfind = true;
                        } else if (psize.height > nHeight) {
                            if (setheight == 0)
                                setheight = psize.height;
                            else if (setheight > psize.height)
                                setheight = psize.height;
                        }
                    }
                }

                if (bfind)
                    parameters.setPreviewSize(nWidth, nHeight);
                else if (setheight != 0)
                    parameters.setPreviewSize(nWidth, setheight);
                else
                    parameters.setPreviewSize(nWidth, nHeight);


                mCamera.setDisplayOrientation(orientation);
                try {
                    mCamera.setParameters(parameters);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                Camera.Size csize = mCamera.getParameters().getPreviewSize();
                getwidth = csize.width;
                getheight = csize.height;
                getformat = mCamera.getParameters().getPreviewFormat();
                csize = mCamera.getParameters().getPictureSize();
                mCamera.setPreviewCallback(new StreamFramecb());

                mCamera.startPreview();
                bIfPreview = true;

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @SuppressLint("NewApi")
    private void OpenCam(SurfaceHolder holder, boolean bFront) {

        if (android.os.Build.VERSION.SDK_INT <= 9) {
            try {
                mCamera = Camera.open();
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        } else {

            int cameraCount = 0;
            boolean isHasFrontCamera = false;
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            cameraCount = Camera.getNumberOfCameras();


            for (int index = 0; index < cameraCount; index++) {

                Camera.getCameraInfo(index, cameraInfo);

                if (bFront) {
                    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                        isHasFrontCamera = true;

                        try {
                            mCamera = Camera.open(index);

                        } catch (RuntimeException e) {
                            e.printStackTrace();
                        }
                    }
                } else {
                    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                        isHasFrontCamera = false;

                        try {
                            mCamera = Camera.open(index);

                        } catch (RuntimeException e) {
                            e.printStackTrace();
                        }
                    }
                }

            }

            if (false == isHasFrontCamera) {

                try {
                    mCamera = Camera.open();
                } catch (RuntimeException e) {
                    e.printStackTrace();
                }
            }
            int cameraRotationOffset = cameraInfo.orientation;
            if (isHasFrontCamera == false)
                cameraRotationOffset += 180;
            int rotate = (360 + cameraRotationOffset - 90) % 360;
            int displayRotation;
            displayRotation = (cameraRotationOffset - 90 + 360) % 360;
            mCamera.setDisplayOrientation(displayRotation);
        }
        try {
            mCamera.setPreviewDisplay(mholder);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    //显示本地视频
    private class nativeSurfaceListener implements SurfaceHolder.Callback {

        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                                   int height) {
            initCamera();
        }

        public void surfaceCreated(SurfaceHolder holder) {
            OpenCam(holder, mbfront);
        }

        public synchronized void surfaceDestroyed(SurfaceHolder holder) {
            if (mCamera != null) {
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
                bIfPreview = false;
            }
        }
    }


    private void NV21ToNV12(byte[] nv21, byte[] nv12, int width, int height) {
        if (nv21 == null || nv12 == null) return;
        int framesize = width * height;
        int i = 0, j = 0;
        System.arraycopy(nv21, 0, nv12, 0, framesize);
        for (i = 0; i < framesize; i++) {
            nv12[i] = nv21[i];
        }
        for (j = 0; j < framesize / 2; j += 2) {
            nv12[framesize + j - 1] = nv21[j + framesize];
        }
        for (j = 0; j < framesize / 2; j += 2) {
            nv12[framesize + j] = nv21[j + framesize - 1];
        }
    }


    private static byte[] rgb2YCbCr420(int[] pixels, int width, int height) {
        int len = width * height;

        byte[] yuv = new byte[len * 3 / 2];
        int y, u, v;
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int rgb = pixels[i * width + j] & 0x00FFFFFF;
                int r = rgb & 0xFF;
                int g = (rgb >> 8) & 0xFF;
                int b = (rgb >> 16) & 0xFF;

                y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
                u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
                v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;

                y = y < 16 ? 16 : (y > 255 ? 255 : y);
                u = u < 0 ? 0 : (u > 255 ? 255 : u);
                v = v < 0 ? 0 : (v > 255 ? 255 : v);
                // 璧嬪��
                yuv[i * width + j] = (byte) y;
                yuv[len + (i >> 1) * width + (j & ~1) + 0] = (byte) u;
                yuv[len + +(i >> 1) * width + (j & ~1) + 1] = (byte) v;
            }
        }
        return yuv;
    }

    private static byte[] getYUVByBitmap(Bitmap bitmap) {
        if (bitmap == null) {
            return null;
        }
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        int size = width * height;

        int pixels[] = new int[size];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);


        byte[] data = rgb2YCbCr420(pixels, width, height);

        return data;
    }

    private Bitmap rotateBitmap(Bitmap origin, float alpha) {
        if (origin == null) {
            return null;
        }
        int width = origin.getWidth();
        int height = origin.getHeight();
        Matrix matrix = new Matrix();
        matrix.setRotate(alpha);

        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
        if (newBM.equals(origin)) {
            return newBM;
        }
        origin.recycle();
        return newBM;
    }

    class StreamFramecb implements Camera.PreviewCallback {

        @SuppressLint("NewApi")
        public void onPreviewFrame(byte[] data, Camera camera) {
            Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
            getsize = data.length;
            byte[] result;
            if (mbfront)
                result = Util.rotateNV21Negative90(data, previewSize.width, previewSize.height);
            else
                result = Util.rotateNV21Degree90(data, previewSize.width, previewSize.height);

            int textheight = my + 10;
            Bitmap bitmap = Bitmap.createBitmap(previewSize.height, textheight, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            Paint paint = new Paint();
            paint.setColor(mcolor);
            paint.setTypeface(mfont);
            paint.setTextSize(mtextsize);

            canvas.drawText(mosd, mx, my, paint);
            byte[] bytes1;
            if (mbfront) {
                Matrix vMatrix = new Matrix();
                vMatrix.postScale(-1, 1);
                Bitmap vB2 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth() // 宽度
                        , bitmap.getHeight() // 高度
                        , vMatrix, true);
                bytes1 = getYUVByBitmap(vB2);
            } else {
                bytes1 = getYUVByBitmap(bitmap);
            }

            for (int i = 0; i < previewSize.height; i++) {
                for (int j = 0; j < textheight; j++) {
                    byte b = bytes1[j * previewSize.height + i];
                    if (b == 0x10) {
                        continue;
                    }
                    if (mcolor == Color.WHITE) {

                        if (result[j * previewSize.height + i] >= 0 && result[j * previewSize.height + i] <= 0x60) {
                            result[j * previewSize.height + i] = (byte) 0xff;
                        } else {
                            result[j * previewSize.height + i] = 0;
                        }

                    } else
                        result[j * previewSize.height + i] = b;
                }
            }
            for (int i = 0; i < previewSize.height; i++) {
                for (int j = 0; j < textheight / 2; j++) {
                    byte b = bytes1[j * previewSize.height + i + previewSize.height * textheight];
                    if (b == (byte) 0x80) {
                        continue;
                    }
                    result[j * previewSize.height + i + previewSize.height * previewSize.width] = b;
                }
            }
            if (mavcapcallback != null) {
                NV21ToNV12(result, videoBuffer, nHeight, nWidth);
                mavcapcallback.OnVideoCallBack(videoBuffer, nWidth * nHeight * 3 / 2);
            }
        }
    }

}
